using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Msg
{
    class VkMsg
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern uint MapVirtualKey(uint uCode, uint uMapType);
        [DllImport("user32.Dll", EntryPoint = "PostMessageA")]
        static extern IntPtr PostMessageA(IntPtr hWnd, uint msg, int wParam, int lParam);
        [DllImport("user32.Dll", EntryPoint = "PostMessageW")]
        static extern IntPtr PostMessageW(IntPtr hWnd, uint msg, int wParam, int lParam);
        [DllImport("user32.Dll", EntryPoint = "SendMessageA")]
        static extern IntPtr SendMessageA(IntPtr hWnd, uint msg, int wParam, int lParam);
        [DllImport("user32.Dll", EntryPoint = "SendMessageW")]
        static extern IntPtr SendMessageW(IntPtr hWnd, uint msg, int wParam, int lParam);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetCursorPos(out Point lpPoint);
        [DllImport("user32.dll")]
        static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint);

        private IntPtr _handle;
        private readonly bool _useSendMessage;
        private readonly bool _usePostMessage;
        private readonly bool _isUnicode;

        protected VkMsg(IntPtr handle, bool useSendMessage, bool usePostMessage, bool isUnicode)
        {
            this._handle = handle;
            this._useSendMessage = useSendMessage;
            this._usePostMessage = usePostMessage;
            this._isUnicode = isUnicode;
        }

        public void SetHandle(IntPtr hwnd)
        {
            this._handle = hwnd;
        }

        public void KeyDown(VirtualKeys vk)
        {
            PlaceMessage((uint)WMsg.WM_KEYDOWN, (int)vk, MakeLp(vk, WMsg.WM_KEYDOWN));
        }
        public void KeyUp(VirtualKeys vk)
        {
            PlaceMessage((uint)WMsg.WM_KEYUP, (int)vk, MakeLp(vk, WMsg.WM_KEYUP));
        }
        public void Active()
        {
            PlaceMessage((uint)WMsg.WM_ACTIVATE, (int)1, 0);
        }

        public void Go(uint x,uint y)
        {
            var lparam = (uint) ((y<<16)|x);

            PlaceMessage((uint)WMsg.WM_MOUSEMOVE, (int)0, (int) lparam);
        }

        public void LClick()
        {
            Point lpPoint;
            GetCursorPos(out lpPoint);
            ScreenToClient(_handle, ref lpPoint);

            PlaceMessage((uint)WMsg.WM_LBUTTONDOWN, 0, lpPoint.X | (lpPoint.Y<<16));
            PlaceMessage((uint)WMsg.WM_LBUTTONUP, 0, lpPoint.X | (lpPoint.Y << 16));
        }
        public void LClickAbs(int x,int y)
        {
            PlaceMessage((uint)WMsg.WM_LBUTTONDOWN, 0, x| (y << 16));
            PlaceMessage((uint)WMsg.WM_LBUTTONUP, 0, x | (y << 16));
        }
        public void RClickAbs(int x, int y)
        {
            PlaceMessage((uint)WMsg.WM_RBUTTONDOWN, 0, x | (y << 16));
            PlaceMessage((uint)WMsg.WM_RBUTTONUP, 0, x | (y << 16));
        }
        public void LClickClient(int x, int y)
        {
            Point lpPoint=new Point(x,y);
            ScreenToClient(_handle, ref lpPoint);
            PlaceMessage((uint)WMsg.WM_LBUTTONDOWN, 0, lpPoint.X | (lpPoint.Y << 16));
            PlaceMessage((uint)WMsg.WM_LBUTTONUP, 0, lpPoint.X | (lpPoint.Y << 16));
        }
        public void RClickClient(int x, int y)
        {
            Point lpPoint = new Point(x, y);
            ScreenToClient(_handle, ref lpPoint);
            PlaceMessage((uint)WMsg.WM_RBUTTONDOWN, 0, lpPoint.X | (lpPoint.Y << 16));
            PlaceMessage((uint)WMsg.WM_RBUTTONUP, 0, lpPoint.X | (lpPoint.Y << 16));
        }

        private void PlaceMessage(uint msg, int vk, int makeLp)
        {
            if (true == this._isUnicode)
            {
                if (true == this._useSendMessage)
                {
                    SendMessageW(_handle, msg, vk, makeLp);
                }
                if (true == this._usePostMessage)
                {
                    PostMessageW(_handle, msg, vk, makeLp);
                }
            }
            else
            {
                if (true == this._useSendMessage)
                {
                    SendMessageA(_handle, msg, vk, makeLp);
                }
                if (true == this._usePostMessage)
                {
                    PostMessageA(_handle, msg, vk, makeLp);
                }
            }
        }


        private static int MakeLp(VirtualKeys vk, int wmKey)
        {
            uint scanCode = MapVirtualKey((uint)vk, 0);
            uint lParam = 0;
            lParam = (0x00000001 | (scanCode << 16));
            if (wmKey != WMsg.WM_KEYDOWN)
            {
                lParam |= 0xc0000000;
            }
            return (int)lParam;
        }

        /// <summary>
        /// Enumeration for virtual keys.
        /// </summary>
        public enum VirtualKeys
            : ushort
        {
            LeftButton = 0x01,
            RightButton = 0x02,
            Cancel = 0x03,
            MiddleButton = 0x04,
            ExtraButton1 = 0x05,
            ExtraButton2 = 0x06,
            Back = 0x08,
            Tab = 0x09,
            Clear = 0x0C,
            Return = 0x0D,
            Shift = 0x10,
            Control = 0x11,
            Menu = 0x12,
            Pause = 0x13,
            CapsLock = 0x14,
            Kana = 0x15,
            Hangeul = 0x15,
            Hangul = 0x15,
            Junja = 0x17,
            Final = 0x18,
            Hanja = 0x19,
            Kanji = 0x19,
            Escape = 0x1B,
            Convert = 0x1C,
            NonConvert = 0x1D,
            Accept = 0x1E,
            ModeChange = 0x1F,
            Space = 0x20,
            Prior = 0x21,
            Next = 0x22,
            End = 0x23,
            Home = 0x24,
            Left = 0x25,
            Up = 0x26,
            Right = 0x27,
            Down = 0x28,
            Select = 0x29,
            Print = 0x2A,
            Execute = 0x2B,
            Snapshot = 0x2C,
            Insert = 0x2D,
            Delete = 0x2E,
            Help = 0x2F,
            N0 = 0x30,
            N1 = 0x31,
            N2 = 0x32,
            N3 = 0x33,
            N4 = 0x34,
            N5 = 0x35,
            N6 = 0x36,
            N7 = 0x37,
            N8 = 0x38,
            N9 = 0x39,
            A = 0x41,
            B = 0x42,
            C = 0x43,
            D = 0x44,
            E = 0x45,
            F = 0x46,
            G = 0x47,
            H = 0x48,
            I = 0x49,
            J = 0x4A,
            K = 0x4B,
            L = 0x4C,
            M = 0x4D,
            N = 0x4E,
            O = 0x4F,
            P = 0x50,
            Q = 0x51,
            R = 0x52,
            S = 0x53,
            T = 0x54,
            U = 0x55,
            V = 0x56,
            W = 0x57,
            X = 0x58,
            Y = 0x59,
            Z = 0x5A,
            LeftWindows = 0x5B,
            RightWindows = 0x5C,
            Application = 0x5D,
            Sleep = 0x5F,
            Numpad0 = 0x60,
            Numpad1 = 0x61,
            Numpad2 = 0x62,
            Numpad3 = 0x63,
            Numpad4 = 0x64,
            Numpad5 = 0x65,
            Numpad6 = 0x66,
            Numpad7 = 0x67,
            Numpad8 = 0x68,
            Numpad9 = 0x69,
            Multiply = 0x6A,
            Add = 0x6B,
            Separator = 0x6C,
            Subtract = 0x6D,
            Decimal = 0x6E,
            Divide = 0x6F,
            F1 = 0x70,
            F2 = 0x71,
            F3 = 0x72,
            F4 = 0x73,
            F5 = 0x74,
            F6 = 0x75,
            F7 = 0x76,
            F8 = 0x77,
            F9 = 0x78,
            F10 = 0x79,
            F11 = 0x7A,
            F12 = 0x7B,
            F13 = 0x7C,
            F14 = 0x7D,
            F15 = 0x7E,
            F16 = 0x7F,
            F17 = 0x80,
            F18 = 0x81,
            F19 = 0x82,
            F20 = 0x83,
            F21 = 0x84,
            F22 = 0x85,
            F23 = 0x86,
            F24 = 0x87,
            NumLock = 0x90,
            ScrollLock = 0x91,
            NEC_Equal = 0x92,
            Fujitsu_Jisho = 0x92,
            Fujitsu_Masshou = 0x93,
            Fujitsu_Touroku = 0x94,
            Fujitsu_Loya = 0x95,
            Fujitsu_Roya = 0x96,
            LeftShift = 0xA0,
            RightShift = 0xA1,
            LeftControl = 0xA2,
            RightControl = 0xA3,
            LeftMenu = 0xA4,
            RightMenu = 0xA5,
            BrowserBack = 0xA6,
            BrowserForward = 0xA7,
            BrowserRefresh = 0xA8,
            BrowserStop = 0xA9,
            BrowserSearch = 0xAA,
            BrowserFavorites = 0xAB,
            BrowserHome = 0xAC,
            VolumeMute = 0xAD,
            VolumeDown = 0xAE,
            VolumeUp = 0xAF,
            MediaNextTrack = 0xB0,
            MediaPrevTrack = 0xB1,
            MediaStop = 0xB2,
            MediaPlayPause = 0xB3,
            LaunchMail = 0xB4,
            LaunchMediaSelect = 0xB5,
            LaunchApplication1 = 0xB6,
            LaunchApplication2 = 0xB7,
            OEM1 = 0xBA,
            OEMPlus = 0xBB,
            OEMComma = 0xBC,
            OEMMinus = 0xBD,
            OEMPeriod = 0xBE,
            OEM2 = 0xBF,
            OEM3 = 0xC0,
            OEM4 = 0xDB,
            OEM5 = 0xDC,
            OEM6 = 0xDD,
            OEM7 = 0xDE,
            OEM8 = 0xDF,
            OEMAX = 0xE1,
            OEM102 = 0xE2,
            ICOHelp = 0xE3,
            ICO00 = 0xE4,
            ProcessKey = 0xE5,
            ICOClear = 0xE6,
            Packet = 0xE7,
            OEMReset = 0xE9,
            OEMJump = 0xEA,
            OEMPA1 = 0xEB,
            OEMPA2 = 0xEC,
            OEMPA3 = 0xED,
            OEMWSCtrl = 0xEE,
            OEMCUSel = 0xEF,
            OEMATTN = 0xF0,
            OEMFinish = 0xF1,
            OEMCopy = 0xF2,
            OEMAuto = 0xF3,
            OEMENLW = 0xF4,
            OEMBackTab = 0xF5,
            ATTN = 0xF6,
            CRSel = 0xF7,
            EXSel = 0xF8,
            EREOF = 0xF9,
            Play = 0xFA,
            Zoom = 0xFB,
            Noname = 0xFC,
            PA1 = 0xFD,
            OEMClear = 0xFE
        }
        static class WMsg
        {
            public static int WM_ACTIVATE = 0x0006;
            public static int WM_ACTIVATEAPP = 0x001C;
            public static int WM_AFXFIRST = 0x0360;
            public static int WM_AFXLAST = 0x037F;
            public static int WM_APP = 0x8000;
            public static int WM_ASKCBFORMATNAME = 0x030C;
            public static int WM_CANCELJOURNAL = 0x004B;
            public static int WM_CANCELMODE = 0x001F;
            public static int WM_CAPTURECHANGED = 0x0215;
            public static int WM_CHANGECBCHAIN = 0x030D;
            public static int WM_CHANGEUISTATE = 0x0127;
            public static int WM_CHAR = 0x0102;
            public static int WM_CHARTOITEM = 0x002F;
            public static int WM_CHILDACTIVATE = 0x0022;
            public static int WM_CLEAR = 0x0303;
            public static int WM_CLOSE = 0x0010;
            public static int WM_COMMAND = 0x0111;
            public static int WM_COMPACTING = 0x0041;
            public static int WM_COMPAREITEM = 0x0039;
            public static int WM_CONTEXTMENU = 0x007B;
            public static int WM_COPY = 0x0301;
            public static int WM_COPYDATA = 0x004A;
            public static int WM_CREATE = 0x0001;
            public static int WM_CTLCOLORBTN = 0x0135;
            public static int WM_CTLCOLORDLG = 0x0136;
            public static int WM_CTLCOLOREDIT = 0x0133;
            public static int WM_CTLCOLORLISTBOX = 0x0134;
            public static int WM_CTLCOLORMSGBOX = 0x0132;
            public static int WM_CTLCOLORSCROLLBAR = 0x0137;
            public static int WM_CTLCOLORSTATIC = 0x0138;
            public static int WM_CUT = 0x0300;
            public static int WM_DEADCHAR = 0x0103;
            public static int WM_DELETEITEM = 0x002D;
            public static int WM_DESTROY = 0x0002;
            public static int WM_DESTROYCLIPBOARD = 0x0307;
            public static int WM_DEVICECHANGE = 0x0219;
            public static int WM_DEVMODECHANGE = 0x001B;
            public static int WM_DISPLAYCHANGE = 0x007E;
            public static int WM_DRAWCLIPBOARD = 0x0308;
            public static int WM_DRAWITEM = 0x002B;
            public static int WM_DROPFILES = 0x0233;
            public static int WM_ENABLE = 0x000A;
            public static int WM_ENDSESSION = 0x0016;
            public static int WM_ENTERIDLE = 0x0121;
            public static int WM_ENTERMENULOOP = 0x0211;
            public static int WM_ENTERSIZEMOVE = 0x0231;
            public static int WM_ERASEBKGND = 0x0014;
            public static int WM_EXITMENULOOP = 0x0212;
            public static int WM_EXITSIZEMOVE = 0x0232;
            public static int WM_FONTCHANGE = 0x001D;
            public static int WM_GETDLGCODE = 0x0087;
            public static int WM_GETFONT = 0x0031;
            public static int WM_GETHOTKEY = 0x0033;
            public static int WM_GETICON = 0x007F;
            public static int WM_GETMINMAXINFO = 0x0024;
            public static int WM_GETOBJECT = 0x003D;
            public static int WM_GETTEXT = 0x000D;
            public static int WM_GETTEXTLENGTH = 0x000E;
            public static int WM_HANDHELDFIRST = 0x0358;
            public static int WM_HANDHELDLAST = 0x035F;
            public static int WM_HELP = 0x0053;
            public static int WM_HOTKEY = 0x0312;
            public static int WM_HSCROLL = 0x0114;
            public static int WM_HSCROLLCLIPBOARD = 0x030E;
            public static int WM_ICONERASEBKGND = 0x0027;
            public static int WM_IME_CHAR = 0x0286;
            public static int WM_IME_COMPOSITION = 0x010F;
            public static int WM_IME_COMPOSITIONFULL = 0x0284;
            public static int WM_IME_CONTROL = 0x0283;
            public static int WM_IME_ENDCOMPOSITION = 0x010E;
            public static int WM_IME_KEYDOWN = 0x0290;
            public static int WM_IME_KEYLAST = 0x010F;
            public static int WM_IME_KEYUP = 0x0291;
            public static int WM_IME_NOTIFY = 0x0282;
            public static int WM_IME_REQUEST = 0x0288;
            public static int WM_IME_SELECT = 0x0285;
            public static int WM_IME_SETCONTEXT = 0x0281;
            public static int WM_IME_STARTCOMPOSITION = 0x010D;
            public static int WM_INITDIALOG = 0x0110;
            public static int WM_INITMENU = 0x0116;
            public static int WM_INITMENUPOPUP = 0x0117;
            public static int WM_INPUTLANGCHANGE = 0x0051;
            public static int WM_INPUTLANGCHANGEREQUEST = 0x0050;
            public static int WM_KEYDOWN = 0x0100;
            public static int WM_KEYFIRST = 0x0100;
            public static int WM_KEYLAST = 0x0108;
            public static int WM_KEYUP = 0x0101;
            public static int WM_KILLFOCUS = 0x0008;
            public static int WM_LBUTTONDBLCLK = 0x0203;
            public static int WM_LBUTTONDOWN = 0x0201;
            public static int WM_LBUTTONUP = 0x0202;
            public static int WM_MBUTTONDBLCLK = 0x0209;
            public static int WM_MBUTTONDOWN = 0x0207;
            public static int WM_MBUTTONUP = 0x0208;
            public static int WM_MDIACTIVATE = 0x0222;
            public static int WM_MDICASCADE = 0x0227;
            public static int WM_MDICREATE = 0x0220;
            public static int WM_MDIDESTROY = 0x0221;
            public static int WM_MDIGETACTIVE = 0x0229;
            public static int WM_MDIICONARRANGE = 0x0228;
            public static int WM_MDIMAXIMIZE = 0x0225;
            public static int WM_MDINEXT = 0x0224;
            public static int WM_MDIREFRESHMENU = 0x0234;
            public static int WM_MDIRESTORE = 0x0223;
            public static int WM_MDISETMENU = 0x0230;
            public static int WM_MDITILE = 0x0226;
            public static int WM_MEASUREITEM = 0x002C;
            public static int WM_MENUCHAR = 0x0120;
            public static int WM_MENUCOMMAND = 0x0126;
            public static int WM_MENUDRAG = 0x0123;
            public static int WM_MENUGETOBJECT = 0x0124;
            public static int WM_MENURBUTTONUP = 0x0122;
            public static int WM_MENUSELECT = 0x011F;
            public static int WM_MOUSEACTIVATE = 0x0021;
            public static int WM_MOUSEFIRST = 0x0200;
            public static int WM_MOUSEHOVER = 0x02A1;
            public static int WM_MOUSELAST = 0x020D;
            public static int WM_MOUSELEAVE = 0x02A3;
            public static int WM_MOUSEMOVE = 0x0200;
            public static int WM_MOUSEWHEEL = 0x020A;
            public static int WM_MOUSEHWHEEL = 0x020E;
            public static int WM_MOVE = 0x0003;
            public static int WM_MOVING = 0x0216;
            public static int WM_NCACTIVATE = 0x0086;
            public static int WM_NCCALCSIZE = 0x0083;
            public static int WM_NCCREATE = 0x0081;
            public static int WM_NCDESTROY = 0x0082;
            public static int WM_NCHITTEST = 0x0084;
            public static int WM_NCLBUTTONDBLCLK = 0x00A3;
            public static int WM_NCLBUTTONDOWN = 0x00A1;
            public static int WM_NCLBUTTONUP = 0x00A2;
            public static int WM_NCMBUTTONDBLCLK = 0x00A9;
            public static int WM_NCMBUTTONDOWN = 0x00A7;
            public static int WM_NCMBUTTONUP = 0x00A8;
            public static int WM_NCMOUSEHOVER = 0x02A0;
            public static int WM_NCMOUSELEAVE = 0x02A2;
            public static int WM_NCMOUSEMOVE = 0x00A0;
            public static int WM_NCPAINT = 0x0085;
            public static int WM_NCRBUTTONDBLCLK = 0x00A6;
            public static int WM_NCRBUTTONDOWN = 0x00A4;
            public static int WM_NCRBUTTONUP = 0x00A5;
            public static int WM_NCXBUTTONDBLCLK = 0x00AD;
            public static int WM_NCXBUTTONDOWN = 0x00AB;
            public static int WM_NCXBUTTONUP = 0x00AC;
            public static int WM_NCUAHDRAWCAPTION = 0x00AE;
            public static int WM_NCUAHDRAWFRAME = 0x00AF;
            public static int WM_NEXTDLGCTL = 0x0028;
            public static int WM_NEXTMENU = 0x0213;
            public static int WM_NOTIFY = 0x004E;
            public static int WM_NOTIFYFORMAT = 0x0055;
            public static int WM_NULL = 0x0000;
            public static int WM_PAINT = 0x000F;
            public static int WM_PAINTCLIPBOARD = 0x0309;
            public static int WM_PAINTICON = 0x0026;
            public static int WM_PALETTECHANGED = 0x0311;
            public static int WM_PALETTEISCHANGING = 0x0310;
            public static int WM_PARENTNOTIFY = 0x0210;
            public static int WM_PASTE = 0x0302;
            public static int WM_PENWINFIRST = 0x0380;
            public static int WM_PENWINLAST = 0x038F;
            public static int WM_POWER = 0x0048;
            public static int WM_POWERBROADCAST = 0x0218;
            public static int WM_PRINT = 0x0317;
            public static int WM_PRINTCLIENT = 0x0318;
            public static int WM_QUERYDRAGICON = 0x0037;
            public static int WM_QUERYENDSESSION = 0x0011;
            public static int WM_QUERYNEWPALETTE = 0x030F;
            public static int WM_QUERYOPEN = 0x0013;
            public static int WM_QUEUESYNC = 0x0023;
            public static int WM_QUIT = 0x0012;
            public static int WM_RBUTTONDBLCLK = 0x0206;
            public static int WM_RBUTTONDOWN = 0x0204;
            public static int WM_RBUTTONUP = 0x0205;
            public static int WM_RENDERALLFORMATS = 0x0306;
            public static int WM_RENDERFORMAT = 0x0305;
            public static int WM_SETCURSOR = 0x0020;
            public static int WM_SETFOCUS = 0x0007;
            public static int WM_SETFONT = 0x0030;
            public static int WM_SETHOTKEY = 0x0032;
            public static int WM_SETICON = 0x0080;
            public static int WM_SETREDRAW = 0x000B;
            public static int WM_SETTEXT = 0x000C;
            public static int WM_SETTINGCHANGE = 0x001A;
            public static int WM_SHOWWINDOW = 0x0018;
            public static int WM_SIZE = 0x0005;
            public static int WM_SIZECLIPBOARD = 0x030B;
            public static int WM_SIZING = 0x0214;
            public static int WM_SPOOLERSTATUS = 0x002A;
            public static int WM_STYLECHANGED = 0x007D;
            public static int WM_STYLECHANGING = 0x007C;
            public static int WM_SYNCPAINT = 0x0088;
            public static int WM_SYSCHAR = 0x0106;
            public static int WM_SYSCOLORCHANGE = 0x0015;
            public static int WM_SYSCOMMAND = 0x0112;
            public static int WM_SYSDEADCHAR = 0x0107;
            public static int WM_SYSKEYDOWN = 0x0104;
            public static int WM_SYSKEYUP = 0x0105;
            public static int WM_TCARD = 0x0052;
            public static int WM_TIMECHANGE = 0x001E;
            public static int WM_TIMER = 0x0113;
            public static int WM_UNDO = 0x0304;
            public static int WM_UNINITMENUPOPUP = 0x0125;
            public static int WM_USER = 0x0400;
            public static int WM_USERCHANGED = 0x0054;
            public static int WM_VKEYTOITEM = 0x002E;
            public static int WM_VSCROLL = 0x0115;
            public static int WM_VSCROLLCLIPBOARD = 0x030A;
            public static int WM_WINDOWPOSCHANGED = 0x0047;
            public static int WM_WINDOWPOSCHANGING = 0x0046;
            public static int WM_WININICHANGE = 0x001A;
            public static int WM_XBUTTONDBLCLK = 0x020D;
            public static int WM_XBUTTONDOWN = 0x020B;
            public static int WM_XBUTTONUP = 0x020C;
        }
    }
}
